#!/usr/bin/env node
/**
 * Auto Trade 管理客户端 v1.2
 *
 * 作用：
 *  1. 从后台管理系统读取账号有效配置，并写入现有的 config.json
 *  2. 拉取账号的 Cookies/CSRF，作为环境变量传给原始 auto-trade.js
 *  3. 启动并托管原始 auto-trade.js，监听其输出中的交易日志
 *  4. 解析交易结果并调用后台的 /api/trade-logs 接口上报
 *
 * 注意：
 *  - 不修改原有 auto-trade.js 的任何代码
 *  - 交易相关逻辑依旧由 auto-trade.js 完成，本文件只负责配置、托管与日志上传
 */

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const { spawn } = require('child_process');
const readline = require('readline');

const DEFAULT_INTERVAL = 300_000;
const CONFIG_PATH = path.resolve(__dirname, 'config.json');

const args = parseArgs(process.argv);
const baseUrl = args.baseUrl || process.env.WEB3_BASE_URL || 'http://localhost:8080';
const token = args.token || process.env.WEB3_TOKEN || '';
const checkInterval = Number(args.checkInterval || process.env.WEB3_CHECK_INTERVAL || 60_000); // 检查间隔，默认1分钟
const dryRun = Boolean(args.dryRun || process.env.WEB3_DRY_RUN);

if (!token) {
  console.error('[auto-trade-client] 缺少 token 参数，例如 --token=acct-1-xxxxx');
  process.exit(1);
}

const api = axios.create({
  baseURL: baseUrl,
  headers: Object.assign({ 'Content-Type': 'application/json' }, token ? { Authorization: `Bearer ${token}` } : {})
});

let childProcess = null;
let childStartedAt = 0;
let backupConfigContent = null;
let currentConfigId = null;
let currentBuyAmount = 0;
let pendingRestartConfirm = false;
let isManualRestart = false;
let isIdleWaiting = false; // 空转等待状态

async function fetchConfig() {
  console.info('[auto-trade-client] 开始获取配置...');

  try {
    console.info('[auto-trade-client] 正在请求后端配置...');
    const [effectiveRes, accountRes, systemRes] = await Promise.all([
      api.get('/api/client/effective-config'),
      api.get('/api/client/account'),
      api.get('/api/system/settings').catch((err) => {
        console.warn('[auto-trade-client] 获取系统设置失败:', err.message);
        return { data: { data: [] } };
      })
    ]);

    console.info('[auto-trade-client] API响应状态:', {
      effective: effectiveRes.status,
      account: accountRes.status,
      system: systemRes.status
    });

    const effectiveData = (effectiveRes.data && effectiveRes.data.data) || effectiveRes.data;
    const accountData = (accountRes.data && accountRes.data.data) || accountRes.data;
    const systemData = (systemRes.data && systemRes.data.data) || systemRes.data || [];

    console.info('[auto-trade-client] 原始系统数据:', systemData);

    if (!effectiveData || !effectiveData.effectiveConfig) {
      throw new Error('后台返回的有效配置为空');
    }

    const activeConfig = effectiveData.activeAccountConfig || {};
    const effectiveConfig = effectiveData.effectiveConfig || {};

    // 解析系统设置
    const systemSettings = {};

    // 如果是从 /api/system/settings/random-sleep 获取的直接配置对象
    if (systemData && typeof systemData === 'object' && !Array.isArray(systemData)) {
      systemSettings.random_sleep_config = systemData;
      console.info('[auto-trade-client] 获取到随机休眠配置:', systemData);
    }
    // 如果是从 /api/system/settings 获取的设置数组
    else if (Array.isArray(systemData)) {
      systemData.forEach(setting => {
        try {
          systemSettings[setting.settingKey] = JSON.parse(setting.settingValue);
        } catch (e) {
          console.warn(`解析系统设置失败: ${setting.settingKey}`, e);
        }
      });
    } else {
      console.warn('[auto-trade-client] 未获取到有效的系统设置，使用默认值');
    }

    const configForScript = {
      name: effectiveConfig.projectName || activeConfig.projectName || effectiveConfig.name || 'Web3 Project',
      baseAsset: effectiveConfig.baseAsset || activeConfig.baseAsset,
      quoteAsset: effectiveConfig.quoteAsset || activeConfig.quoteAsset || 'USDT',
      chainId: Number(effectiveConfig.chainId || activeConfig.chainId || 56),
      contractAddress: effectiveConfig.contractAddress || activeConfig.contractAddress,
      buyAmount: Number(effectiveConfig.buyAmount || activeConfig.buyAmount || 0),
      targetBuyQuote: Number(effectiveConfig.targetBuyQuote || activeConfig.targetBuyQuote || 0),
      proxy: Boolean(effectiveConfig.proxy ?? (activeConfig.proxyEnabled === 1)),
      notifyUrl: effectiveConfig.notifyUrl || activeConfig.notifyUrl || ''
    };

    currentConfigId = activeConfig.id || null;
    currentBuyAmount = configForScript.buyAmount;

    console.info('[auto-trade-client] 配置获取完成');
    return {
      configForScript,
      accountData,
      systemSettings
    };
  } catch (error) {
    console.error('[auto-trade-client] fetchConfig失败:', error.message);
    throw error;
  }
}

function writeConfigFile(configContent) {
  const jsonText = JSON.stringify(configContent, null, 2);
  fs.writeFileSync(CONFIG_PATH, jsonText, 'utf8');
  console.info('[auto-trade-client] 已写入 config.json');
}

function backupConfig() {
  if (fs.existsSync(CONFIG_PATH)) {
    backupConfigContent = fs.readFileSync(CONFIG_PATH, 'utf8');
  }
}

function restoreConfig() {
  if (backupConfigContent !== null) {
    fs.writeFileSync(CONFIG_PATH, backupConfigContent, 'utf8');
    console.info('[auto-trade-client] 已恢复原始 config.json');
  }
}

function spawnAutoTrade(envOverrides, systemSettings = {}) {
  if (childProcess) {
    console.info('[auto-trade-client] 正在结束旧的 auto-trade.js …');
    isManualRestart = true; // 标记为主动重启
    childProcess.kill('SIGTERM');
  }

  // 构建启动参数
  const launchArgs = ['auto-trade.js'];

  // 添加账号ID参数
  const accountIdMatch = token.match(/acct-(\d+)-/);
  if (accountIdMatch) {
    launchArgs.push(`--account-id=${accountIdMatch[1]}`);
  }

  // 添加随机休眠配置参数
  const sleepConfig = systemSettings.random_sleep_config || { enabled: true, min_seconds: 30, max_seconds: 120 };
  launchArgs.push(`--sleep-config=${JSON.stringify(sleepConfig)}`);

  console.info(`[auto-trade-client] 系统设置:`, systemSettings);
  console.info(`[auto-trade-client] 使用的休眠配置:`, sleepConfig);
  console.info(`[auto-trade-client] 启动参数: node ${launchArgs.join(' ')}`);

  childProcess = spawn('node', launchArgs, {
    cwd: __dirname,
    stdio: ['ignore', 'pipe', 'pipe'],
    env: Object.assign({}, process.env, envOverrides)
  });
  childStartedAt = Date.now();

  childProcess.stdout.setEncoding('utf8');
  childProcess.stderr.setEncoding('utf8');

  const rl = readline.createInterface({ input: childProcess.stdout });
  rl.on('line', handleLogLine);

  childProcess.stderr.on('data', (chunk) => {
    const text = chunk.toString();
    process.stderr.write(text);
  });

  childProcess.on('exit', (code, signal) => {
    console.warn(`[auto-trade-client] auto-trade.js 已退出 code=${code} signal=${signal}`);
    if (!isShuttingDown && !isManualRestart) {
      // 只有在非主动重启的情况下才自动重启
      setTimeout(startChildFlow, 5000);
    } else if (isManualRestart) {
      // 重置主动重启标志
      isManualRestart = false;
    }
  });

  console.info('[auto-trade-client] 已启动 auto-trade.js');
}

function handleLogLine(line) {
  process.stdout.write(line + '\n');

  // 检测正常完成的明确标志
  if (line.includes('[CLIENT_SIGNAL] TARGET_ACHIEVED_NORMAL_EXIT') ||
      line.includes('[CLIENT_SIGNAL] NORMAL_EXIT_SIGNAL_DETECTED')) {
    enterIdleWaiting('基础脚本正常完成');
    return;
  }

  // 检测异常情况
  if (detectError(line)) {
    return; // 异常情况已处理，不需要继续处理交易日志
  }

  // 检测auto-trade.js真正启动成功的标志
  if (line.includes('订单总数:') && pendingRestartConfirm) {
    // auto-trade.js已经开始正常运行，可以确认重启完成
    confirmRestart();
  }

  const buySellRegex = /买单成交:\s*([\d.]+)\s*USDT,\s*卖单成交:\s*([\d.]+)\s*USDT,\s*本轮磨损:\s*([\-\d.]+)\s*USDT/;
  const initialBuyRegex = /初始买入完成:\s*([\d.]+)\s*USDT/;

  let payload = null;

  const matchCycle = line.match(buySellRegex);
  if (matchCycle) {
    const actualBuy = parseFloat(matchCycle[1]);
    const actualSell = parseFloat(matchCycle[2]);
    const slippage = parseFloat(matchCycle[3]);
    payload = {
      direction: 'BUY',
      plannedAmount: currentBuyAmount,
      actualAmount: actualBuy,
      slippage: slippage
    };
    if (actualSell > 0) {
      uploadLog(Object.assign({}, payload, {
        direction: 'SELL',
        plannedAmount: actualSell,
        actualAmount: actualSell,
        slippage: 0
      })).catch(printUploadError);
    }
  }

  const matchInitial = line.match(initialBuyRegex);
  if (!payload && matchInitial) {
    const actual = parseFloat(matchInitial[1]);
    payload = {
      direction: 'BUY_INIT',
      plannedAmount: actual,
      actualAmount: actual,
      slippage: 0
    };
  }

  if (payload) {
    uploadLog(payload).catch(printUploadError);
  }
}

function detectError(line) {
  // 检测各种异常情况
  const errorPatterns = [
    /.*失败.*响应异常.*message.*:.*".*"/i,  // 响应异常且有message字段
    /挂.*单失败.*下单失败.*响应异常/i,      // 挂单失败
    /.*失败.*"message".*".*"/i               // 包含message字段的失败
  ];

  for (const pattern of errorPatterns) {
    if (pattern.test(line)) {
      reportError(line);
      enterIdleWaiting('检测到异常: ' + line.substring(0, 100));
      return true;
    }
  }
  return false;
}

async function reportError(errorLine) {
  try {
    await api.post('/api/client/report-error', {
      errorMessage: errorLine,
      errorTime: new Date().toISOString(),
      errorType: 'TRADE_ERROR'
    });
    console.info('[auto-trade-client] 已上报异常信息');
  } catch (error) {
    console.error('[auto-trade-client] 上报异常失败', error?.response?.data || error.message || error);
  }
}

function enterIdleWaiting(reason) {
  if (isIdleWaiting) return;

  isIdleWaiting = true;
  console.info(`[auto-trade-client] 进入空转等待状态: ${reason}`);
  console.info('[auto-trade-client] 等待服务端重启命令...');

  // 停止auto-trade.js
  if (childProcess) {
    console.info('[auto-trade-client] 停止 auto-trade.js');
    isManualRestart = true;
    childProcess.kill('SIGTERM');
    childProcess = null;
  }
}

async function confirmRestart() {
  if (!pendingRestartConfirm) return;

  try {
    await api.post('/api/client/restart-confirm');
    console.info('[auto-trade-client] 已确认重启完成');
    pendingRestartConfirm = false;
  } catch (confirmError) {
    console.error('[auto-trade-client] 重启确认失败', confirmError?.response?.data || confirmError.message || confirmError);
  }
}

async function uploadLog(partial) {
  if (dryRun) {
    console.info('[auto-trade-client] dryRun 模式，不上传日志', partial);
    return;
  }
  const payload = Object.assign({
    accountConfigId: currentConfigId,
    tradeTime: new Date().toISOString(),
    status: 'SUCCESS',
    remark: partial.direction || 'TRADE'
  }, partial);

  await api.post('/api/client/trade-logs', payload);
  // console.info('[auto-trade-client] 已上报交易日志', payload);
}

function printUploadError(error) {
  console.error('[auto-trade-client] 上传日志失败', error?.response?.data || error.message || error);
}

async function checkShouldRestart() {
  try {
    const response = await api.get('/api/client/restart-check');
    const data = (response.data && response.data.data) || response.data;

    if (data.shouldRestart) {
      console.info('[auto-trade-client] 检测到需要重启，准备重启...');
      console.info(`  重启标志: ${data.needsRestart ? '是' : '否'}`);
      console.info(`  上次重启时间: ${data.lastRestartTime || '从未重启'}`);

      // 退出空转状态
      if (isIdleWaiting) {
        isIdleWaiting = false;
        console.info('[auto-trade-client] 退出空转状态，开始重启');
      }

      // 设置待确认标志
      pendingRestartConfirm = true;

      // 执行重启
      await startChildFlow();
    }
  } catch (error) {
    console.error('[auto-trade-client] 重启检查失败', error?.response?.data || error.message || error);
  }
}

async function startChildFlow() {
  if (isIdleWaiting) {
    console.info('[auto-trade-client] 当前处于空转状态，跳过启动');
    return;
  }

  try {
    const { configForScript, accountData, systemSettings } = await fetchConfig();
    writeConfigFile(configForScript);

    spawnAutoTrade({
      COOKIES: accountData.cookies || process.env.COOKIES || '',
      CSRF_TOKEN: accountData.csrfToken || process.env.CSRF_TOKEN || ''
    }, systemSettings);
  } catch (error) {
    console.error('[auto-trade-client] 初始化失败', error?.response?.data || error.message || error);
    if (!isIdleWaiting) {
      setTimeout(startChildFlow, 10_000);
    }
  }
}

let isShuttingDown = false;
function shutdown() {
  if (isShuttingDown) return;
  isShuttingDown = true;
  console.info('\n[auto-trade-client] 收到退出信号，正在清理...');
  if (childProcess) {
    childProcess.kill('SIGTERM');
  }
  restoreConfig();
  setTimeout(() => process.exit(0), 1000);
}

process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
process.on('SIGQUIT', shutdown);

async function main() {
  console.info('[auto-trade-client] 启动成功');
  console.info(`  后台地址: ${baseUrl}`);
  console.info(`  Token: ${token.substring(0, 20)}...`);
  console.info(`  日志上报: ${dryRun ? '禁用' : '启用'}`);
  console.info(`  配置检查间隔: ${checkInterval}ms`);

  backupConfig();
  await startChildFlow();

  // 智能配置检查，只在配置变更时重启
  setInterval(() => {
    if (!isShuttingDown) {
      checkShouldRestart();
    }
  }, checkInterval);

  console.info('[auto-trade-client] 智能重启监控已启动');
}

function parseArgs(argv) {
  const map = {};
  for (let i = 2; i < argv.length; i += 1) {
    const item = argv[i];
    if (!item.startsWith('--')) continue;
    const [key, value] = item.replace(/^--/, '').split('=');
    map[key] = value === undefined ? true : value;
  }
  return map;
}

main();
